﻿using Circus.Utility;
using System;
using System.Reflection;
using System.Web;
using System.Web.SessionState;
using System.Linq;

namespace WoAiPao {

    /// <summary>
    /// 负责处理地址命令并执行调用相应的方法。
    /// </summary>
    public class ApiHandler : IHttpHandler, IRequiresSessionState {

        /// <summary>
        /// 获取执行命令的控制器类名前缀。
        /// </summary>
        internal static readonly string typePrefix = typeof(ApiHandler).Namespace + ".";

        /// <summary>
        /// 获取执行命令的控制器类名后缀。
        /// </summary>
        internal const string typePostfix = "Controller";

        /// <summary>
        /// 获取一个值，该值指示其他请求是否可以使用 <see cref="T:System.Web.IHttpHandler"/> 实例。
        /// </summary>
        /// <returns>
        /// 如果 <see cref="T:System.Web.IHttpHandler"/> 实例可再次使用，则为 true；否则为 false。
        /// </returns>
        public bool IsReusable {
            get {
                return true;
            }
        }

        /// <summary>
        /// 通过实现 <see cref="T:System.Web.IHttpHandler"/> 接口的自定义 HttpHandler 启用 HTTP Web 请求的处理。
        /// </summary>
        /// <param name="context"><see cref="T:System.Web.HttpContext"/> 对象，它提供对用于为 HTTP 请求提供服务的内部服务器对象（如 Request、Response、Session 和 Server）的引用。</param>
        public void ProcessRequest(HttpContext context) {

            #region 解析路径

            var path = context.Request.Path;

            // path: .../commandType/commandName/
            int startIndex = path.Length;

            // 忽略最后一个 '/'
            if (path[startIndex - 1] == '/') {
                startIndex--;
            }

            // 检索 /commandName 的位置。
            var left = lastIndexOf(path, '/', startIndex - 1) + 1;
            var commandName = path.Substring(left, startIndex - left);

            // 跳过命令名。
            startIndex = left - 2;

            // 检索 /commandType/ 的位置。
            left = lastIndexOf(path, '/', startIndex - 1) + 1;
            if (left == 0) {
                reportError("Usage: [ApiRootPath]/ControllerName/MethodName?ParamName1=ParamValue1&ParamName2=ParamValue2");
                return;
            }
            var commandType = String.Concat(typePrefix, char.ToUpperInvariant(path[left]).ToString(), path.Substring(left + 1, startIndex - left), typePostfix);

            #endregion

            #region 查找方法

            // 找到要执行的命令类型。
            var type = typeof(ApiHandler).Assembly.GetType(commandType);
            if (type == null) {
                reportError("404 - Type Not Found: " + commandType);
                return;
            }

            // 找到要执行的命令方法。
            MethodInfo method;
            try {
                method = type.GetMethod(commandName);
            } catch (AmbiguousMatchException) {
                method = type.GetMethods().Where(m => m.Name == commandName).OrderByDescending(m => m.GetParameters().Length).FirstOrDefault();
            }
            if (method == null) {
                reportError("404 - Method Not Found : " + commandType + "." + commandName);
                return;
            }

            #endregion

            #region 查找参数

            // 加载执行的参数。
            var parameters = method.GetParameters();
            var parameterValues = new object[parameters.Length];
            for (int i = 0; i < parameters.Length; i++) {
                var p = parameters[i];
                var arg = context.Request.QueryString[p.Name] ?? context.Request.Form[p.Name];
                if (arg != null) {

                    // 解析参数。
                    if ((parameterValues[i] = parseObject(arg, p.ParameterType)) == null) {

                        // 数组和列表特殊处理。
                        if (typeof(System.Collections.IList).IsAssignableFrom(p.ParameterType)) {
                            var argValues = context.Request.QueryString.GetValues(p.Name) ?? context.Request.Form.GetValues(p.Name);
                            if (p.ParameterType.IsArray) {
                                var el = p.ParameterType.GetElementType();
                                var parsedArray = Array.CreateInstance(el, argValues.Length);
                                for (int j = 0; j < argValues.Length; j++) {
                                    parsedArray.SetValue(parseObject(argValues[j], el), j);
                                }
                                parameterValues[i] = parsedArray;
                            } else {
                                var el = p.ParameterType.IsGenericType ? p.ParameterType.GetGenericArguments()[0] : typeof(object);
                                var parsedList = (System.Collections.IList)Activator.CreateInstance(p.ParameterType);
                                foreach (var argValue in argValues) {
                                    parsedList.Add(parseObject(argValue, el));
                                }
                                parameterValues[i] = parsedList;
                            }

                        }

                    }

                } else if (p.IsDefined(typeof(System.Runtime.InteropServices.OptionalAttribute), false)) {
                    parameterValues[i] = p.DefaultValue;
                }
            }

            #endregion

            #region 执行方法

            // 执行接口方法。
            var result = method.Invoke(null, parameterValues);

            // 输出接口返回值。
            var returnType = method.ReturnType;
            if (returnType == typeof(string)) {
                HttpHelper.jsonp((string)result);
            } else if (returnType != typeof(void)) {
                HttpHelper.jsonp(result);
            }

            #endregion

        }

        private static int lastIndexOf(string value, char ch, int startIndex) {
            for (var i = startIndex; i >= 0; i--) {
                if (value[i] == ch) {
                    return i;
                }
            }
            return -1;
        }

        private static void reportError(string message) {
            HttpContext.Current.Response.StatusCode = 404;
            HttpContext.Current.Response.Write(message);
        }

        /// <summary>
        /// 将指定的字符串解析为指定类型的值。
        /// </summary>
        /// <param name="value">要解析的字符串。</param>
        /// <param name="type">要解析的目标类型。</param>
        /// <returns>返回解析后的对象值。</returns>
        private static object parseObject(string value, Type type) {
            return ConvertHelper.parseObject(value, type);
        }

    }

    /// <summary>
    /// 指示当前接口是一个 GET 接口或当前参数来自 GET 参数。
    /// </summary>
    [AttributeUsage(AttributeTargets.Method | AttributeTargets.Parameter)]
    public sealed class getAttribute : Attribute {

    }

    /// <summary>
    /// 指示当前接口是一个 POST 接口或当前参数来自 POST 参数。
    /// </summary>
    [AttributeUsage(AttributeTargets.Method | AttributeTargets.Parameter)]
    public sealed class postAttribute : Attribute {

    }

}